using System;
using System.Collections.Generic;

namespace Pentago.Core
{
    public class InvalidPositionException : Exception
    {
        public InvalidPositionException(int identifier, int location) : base(String.Format("Position {0}/{1} does not exist.", identifier, location)) { }
    }

    public class PositionOccupiedException : Exception
    {
        public PositionOccupiedException(int identifier, int location) : base(String.Format("Position {0}/{1} is already occupied.", identifier, location)) { }
    }

    public class GameBlock : IGameBlock
    {
        public int Identifier { get { return identifier; } }
        private readonly int identifier;
        IDictionary<int, Marble> block;

        public GameBlock(int identifier)
        {
            this.identifier = identifier;
            block = CreateNewBlock();
        }

        public void Place(int location, Marble colour)
        {
            if (!block.ContainsKey(location))
                throw new InvalidPositionException(identifier, location);

            if (block[location] != Marble.Empty)
                throw new PositionOccupiedException(identifier, location);

            block[location] = colour;
        }

        public void Twist(Direction direction)
        {
            var newBlock = CreateNewBlock();

            if (direction == Direction.Clockwise)  // todo: gross, do something more mathy
            {
                newBlock[3] = block[1];
                newBlock[6] = block[2];
                newBlock[9] = block[3];

                newBlock[2] = block[4];
                newBlock[5] = block[5];
                newBlock[8] = block[6];

                newBlock[1] = block[7];
                newBlock[4] = block[8];
                newBlock[7] = block[9];
            }
            else
            {
                newBlock[7] = block[1];
                newBlock[4] = block[2];
                newBlock[1] = block[3];

                newBlock[8] = block[4];
                newBlock[5] = block[5];
                newBlock[2] = block[6];

                newBlock[9] = block[7];
                newBlock[6] = block[8];
                newBlock[3] = block[9];
            }

            block = newBlock;
        }

        public bool IsOccupiedBy(int location, Marble colour)
        {
            if (!block.ContainsKey(location))
                throw new InvalidPositionException(identifier, location);

            return block[location] == colour;
        }

        public IDictionary<int, Marble> RetrieveAllMarbleLocations() // todo: only used in specs
        {
            return block;
        }

        private IDictionary<int, Marble> CreateNewBlock()
        {
            var block = new Dictionary<int, Marble>(9);

            for (var location = 1; location <= 9; location++)
                block.Add(location, Marble.Empty);

            return block;
        }
    }
}